{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Important: Read this!\n",
    "\n",
    "This recipe does not work with the standard conda environment.\n",
    "\n",
    "If you are in the standard environment, do this:\n",
    "\n",
    "1. Stop Jupyter\n",
    "2. Activate QIIME2 environment on conda\n",
    "3. Do `jupyter serverextension enable --py qiime2 --sys-prefix`\n",
    "4. Start Jupyter inside QIIME2 environment\n",
    "\n",
    "Note that other recipes will not work inside this environment. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Check this out!\n",
    "\n",
    "This is based on on [QIIME2 Fecal Microbiota Transpant example](https://docs.qiime2.org/2018.8/tutorials/fmt/) (for the command line). You are strongly advised to read it before proceeding.\n",
    "\n",
    "There is an [amazing example](http://nbviewer.jupyter.org/gist/tkosciol/29de5198a4be81559a075756c2490fde) of using the Artifact API using the \"Moving Pictures\" tutorial of QIIME 2 produced by Tomasz Kościółek. I use a more convoluted approach than Tomasz's in order to go a little deeper in terms of understanding of the Python internals. That is more of a learning experience on the internals than a practical recommendatin. **My recommendation is to use Tomasz's dialect, not mine**.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Getting the data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!wget https://data.qiime2.org/2018.8/tutorials/fmt/sample_metadata.tsv\n",
    "!wget https://data.qiime2.org/2018.8/tutorials/fmt/fmt-tutorial-demux-1-10p.qza\n",
    "!wget https://data.qiime2.org/2018.8/tutorials/fmt/fmt-tutorial-demux-2-10p.qza"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# The recipe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "from qiime2.metadata.metadata import Metadata\n",
    "from qiime2.metadata.metadata import CategoricalMetadataColumn\n",
    "from qiime2.sdk import Artifact\n",
    "from qiime2.sdk import PluginManager\n",
    "from qiime2.sdk import Result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'alignment': <qiime2.plugin.plugin.Plugin at 0x7f843047e908>,\n",
       " 'composition': <qiime2.plugin.plugin.Plugin at 0x7f8430481be0>,\n",
       " 'cutadapt': <qiime2.plugin.plugin.Plugin at 0x7f8430493ba8>,\n",
       " 'dada2': <qiime2.plugin.plugin.Plugin at 0x7f84301e8dd8>,\n",
       " 'deblur': <qiime2.plugin.plugin.Plugin at 0x7f842fcea668>,\n",
       " 'demux': <qiime2.plugin.plugin.Plugin at 0x7f842fd41f98>,\n",
       " 'diversity': <qiime2.plugin.plugin.Plugin at 0x7f8430466128>,\n",
       " 'emperor': <qiime2.plugin.plugin.Plugin at 0x7f842fc2d8d0>,\n",
       " 'feature-classifier': <qiime2.plugin.plugin.Plugin at 0x7f842fd41668>,\n",
       " 'feature-table': <qiime2.plugin.plugin.Plugin at 0x7f842fd50898>,\n",
       " 'gneiss': <qiime2.plugin.plugin.Plugin at 0x7f843020dac8>,\n",
       " 'longitudinal': <qiime2.plugin.plugin.Plugin at 0x7f84304dc4a8>,\n",
       " 'metadata': <qiime2.plugin.plugin.Plugin at 0x7f843052b978>,\n",
       " 'phylogeny': <qiime2.plugin.plugin.Plugin at 0x7f84304931d0>,\n",
       " 'quality-control': <qiime2.plugin.plugin.Plugin at 0x7f84304e6f60>,\n",
       " 'quality-filter': <qiime2.plugin.plugin.Plugin at 0x7f8430525b38>,\n",
       " 'sample-classifier': <qiime2.plugin.plugin.Plugin at 0x7f8430560a20>,\n",
       " 'taxa': <qiime2.plugin.plugin.Plugin at 0x7f84361b56d8>,\n",
       " 'types': <qiime2.plugin.plugin.Plugin at 0x7f8436254898>,\n",
       " 'vsearch': <qiime2.plugin.plugin.Plugin at 0x7f84361a7f98>}"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pm = PluginManager()\n",
    "demux_plugin = pm.plugins['demux']\n",
    "#demux_emp_single = demux_plugin.actions['emp_single']\n",
    "demux_summarize = demux_plugin.actions['summarize']\n",
    "pm.plugins"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Summarize counts per sample for all samples, and generate interactive positional quality plots based on `n` randomly selected sequences.\n",
      "OrderedDict([('data', ParameterSpec(qiime_type=SampleData[JoinedSequencesWithQuality | PairedEndSequencesWithQuality | SequencesWithQuality], view_type=<class 'q2_demux._summarize._visualizer._PlotQualView'>, default=NOVALUE, description='The demultiplexed sequences to be summarized.'))])\n",
      "OrderedDict([('n', ParameterSpec(qiime_type=Int, view_type=<class 'int'>, default=10000, description='The number of sequences that should be selected at random for quality score plots. The quality plots will present the average positional qualities across all of the sequences selected. If input sequences are paired end, plots will be generated for both forward and reverse reads for the same `n` sequences.'))])\n",
      "OrderedDict([('visualization', ParameterSpec(qiime_type=Visualization, view_type=None, default=NOVALUE, description=NOVALUE))])\n"
     ]
    }
   ],
   "source": [
    "print(demux_summarize.description)\n",
    "demux_summarize_signature = demux_summarize.signature\n",
    "print(demux_summarize_signature.inputs)\n",
    "print(demux_summarize_signature.parameters)\n",
    "print(demux_summarize_signature.outputs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['__add__', '__class__', '__contains__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_fields', 'count', 'index', 'visualization']\n",
      "<class 'qiime2.sdk.result.Visualization'>\n",
      "['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_alias', '_archiver', '_destructor', '_from_data_dir', '_is_valid_type', '_repr_html_', 'citations', 'export_data', 'extension', 'extract', 'format', 'get_index_paths', 'load', 'peek', 'save', 'type', 'uuid']\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div><img onload=\"(function(div, url){\n",
       "if (typeof require !== 'undefined') {\n",
       "    var baseURL = require.toUrl('').split('/').slice(0, -2).join('/');\n",
       "} else {\n",
       "    var baseURL = JSON.parse(\n",
       "        document.getElementById('jupyter-config-data').innerHTML\n",
       "    ).baseUrl.slice(0, -1);\n",
       "}\n",
       "url = baseURL + url;\n",
       "fetch(url).then(function(res) {\n",
       "    if (res.status === 404) {\n",
       "        div.innerHTML = 'Install QIIME 2 Jupyter extension with:<br />' +\n",
       "                        '<code>jupyter serverextension enable --py qiime2' +\n",
       "                        ' --sys-prefix</code><br />then restart your server.' +\n",
       "                        '<br /><br />(Interactive output not available on ' +\n",
       "                        'static notebook viewer services like nbviewer.)';\n",
       "    } else if (res.status === 409) {\n",
       "        div.innerHTML = 'Visualization no longer in scope. Re-run this cell' +\n",
       "                        ' to see the visualization.';\n",
       "    } else if (res.ok) {\n",
       "        url = res.url;\n",
       "        div.innerHTML = '<iframe src=\\'' + url + '\\' style=\\'' +\n",
       "                        'width: 100%; height: 700px; border: 0;\\'>' +\n",
       "                        '</iframe><hr />Open in a: <a href=\\'' + url + '\\'' +\n",
       "                        ' target=\\'_blank\\'>new window</a>'\n",
       "    } else {\n",
       "        div.innerHTML = 'Something has gone wrong. Check notebook server for' +\n",
       "                        ' errors.';\n",
       "    }\n",
       "});\n",
       "})(this.parentElement, '/qiime2/redirect?location=/tmp/qiime2-archive-h44bqnfv')\" src=\"\" /></div>"
      ],
      "text/plain": [
       "<visualization: Visualization uuid: 4aa5fe45-0c6f-4c69-9362-af6aeebf26d7>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "seqs1 = Result.load('fmt-tutorial-demux-1-10p.qza')\n",
    "sum_data1 = demux_summarize(seqs1)\n",
    "\n",
    "print(dir(sum_data1))\n",
    "print(type(sum_data1.visualization))\n",
    "print(dir(sum_data1.visualization))\n",
    "sum_data1.visualization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['__add__', '__class__', '__contains__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_fields', 'count', 'index', 'visualization']\n",
      "<class 'qiime2.sdk.result.Visualization'>\n",
      "['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_alias', '_archiver', '_destructor', '_from_data_dir', '_is_valid_type', '_repr_html_', 'citations', 'export_data', 'extension', 'extract', 'format', 'get_index_paths', 'load', 'peek', 'save', 'type', 'uuid']\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div><img onload=\"(function(div, url){\n",
       "if (typeof require !== 'undefined') {\n",
       "    var baseURL = require.toUrl('').split('/').slice(0, -2).join('/');\n",
       "} else {\n",
       "    var baseURL = JSON.parse(\n",
       "        document.getElementById('jupyter-config-data').innerHTML\n",
       "    ).baseUrl.slice(0, -1);\n",
       "}\n",
       "url = baseURL + url;\n",
       "fetch(url).then(function(res) {\n",
       "    if (res.status === 404) {\n",
       "        div.innerHTML = 'Install QIIME 2 Jupyter extension with:<br />' +\n",
       "                        '<code>jupyter serverextension enable --py qiime2' +\n",
       "                        ' --sys-prefix</code><br />then restart your server.' +\n",
       "                        '<br /><br />(Interactive output not available on ' +\n",
       "                        'static notebook viewer services like nbviewer.)';\n",
       "    } else if (res.status === 409) {\n",
       "        div.innerHTML = 'Visualization no longer in scope. Re-run this cell' +\n",
       "                        ' to see the visualization.';\n",
       "    } else if (res.ok) {\n",
       "        url = res.url;\n",
       "        div.innerHTML = '<iframe src=\\'' + url + '\\' style=\\'' +\n",
       "                        'width: 100%; height: 700px; border: 0;\\'>' +\n",
       "                        '</iframe><hr />Open in a: <a href=\\'' + url + '\\'' +\n",
       "                        ' target=\\'_blank\\'>new window</a>'\n",
       "    } else {\n",
       "        div.innerHTML = 'Something has gone wrong. Check notebook server for' +\n",
       "                        ' errors.';\n",
       "    }\n",
       "});\n",
       "})(this.parentElement, '/qiime2/redirect?location=/tmp/qiime2-archive-yoquvdf_')\" src=\"\" /></div>"
      ],
      "text/plain": [
       "<visualization: Visualization uuid: 88627958-3139-4ac9-bf66-1989dcfdb0ac>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "seqs2 = Result.load('fmt-tutorial-demux-2-10p.qza')\n",
    "sum_data2 = demux_summarize(seqs2)\n",
    "\n",
    "print(dir(sum_data2))\n",
    "print(type(sum_data2.visualization))\n",
    "print(dir(sum_data2.visualization))\n",
    "sum_data2.visualization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Running external command line application(s). This may print messages to stdout and/or stderr.\n",
      "The command(s) being run are below. These commands cannot be manually re-run as they will depend on temporary files that no longer exist.\n",
      "\n",
      "Command: run_dada_single.R /tmp/qiime2-archive-uiodiox5/5db90b62-c6e4-4c09-8c79-c0cdfbe2cea0/data /tmp/tmpeu6ezzg7/output.tsv.biom /tmp/tmpeu6ezzg7/track.tsv /tmp/tmpeu6ezzg7 150 13 2.0 2 Inf consensus 1.0 1 1000000 NULL 16\n",
      "\n"
     ]
    }
   ],
   "source": [
    "#Quality control\n",
    "dada2_plugin = pm.plugins['dada2']\n",
    "dada2_denoise_single = dada2_plugin.actions['denoise_single']\n",
    "qual_control1 = dada2_denoise_single(demultiplexed_seqs=seqs1,\n",
    "                                    trunc_len=150, trim_left=13)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Running external command line application(s). This may print messages to stdout and/or stderr.\n",
      "The command(s) being run are below. These commands cannot be manually re-run as they will depend on temporary files that no longer exist.\n",
      "\n",
      "Command: run_dada_single.R /tmp/qiime2-archive-de622u8k/5f459ea8-c6a8-438e-b42f-35e4f86166d7/data /tmp/tmpi0zda_vn/output.tsv.biom /tmp/tmpi0zda_vn/track.tsv /tmp/tmpi0zda_vn 150 13 2.0 2 Inf consensus 1.0 1 1000000 NULL 16\n",
      "\n"
     ]
    }
   ],
   "source": [
    "qual_control2 = dada2_denoise_single(demultiplexed_seqs=seqs2,\n",
    "                                    trunc_len=150, trim_left=13)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><img onload=\"(function(div, url){\n",
       "if (typeof require !== 'undefined') {\n",
       "    var baseURL = require.toUrl('').split('/').slice(0, -2).join('/');\n",
       "} else {\n",
       "    var baseURL = JSON.parse(\n",
       "        document.getElementById('jupyter-config-data').innerHTML\n",
       "    ).baseUrl.slice(0, -1);\n",
       "}\n",
       "url = baseURL + url;\n",
       "fetch(url).then(function(res) {\n",
       "    if (res.status === 404) {\n",
       "        div.innerHTML = 'Install QIIME 2 Jupyter extension with:<br />' +\n",
       "                        '<code>jupyter serverextension enable --py qiime2' +\n",
       "                        ' --sys-prefix</code><br />then restart your server.' +\n",
       "                        '<br /><br />(Interactive output not available on ' +\n",
       "                        'static notebook viewer services like nbviewer.)';\n",
       "    } else if (res.status === 409) {\n",
       "        div.innerHTML = 'Visualization no longer in scope. Re-run this cell' +\n",
       "                        ' to see the visualization.';\n",
       "    } else if (res.ok) {\n",
       "        url = res.url;\n",
       "        div.innerHTML = '<iframe src=\\'' + url + '\\' style=\\'' +\n",
       "                        'width: 100%; height: 700px; border: 0;\\'>' +\n",
       "                        '</iframe><hr />Open in a: <a href=\\'' + url + '\\'' +\n",
       "                        ' target=\\'_blank\\'>new window</a>'\n",
       "    } else {\n",
       "        div.innerHTML = 'Something has gone wrong. Check notebook server for' +\n",
       "                        ' errors.';\n",
       "    }\n",
       "});\n",
       "})(this.parentElement, '/qiime2/redirect?location=/tmp/qiime2-archive-2upc1mei')\" src=\"\" /></div>"
      ],
      "text/plain": [
       "<visualization: Visualization uuid: 3028e5f9-5aff-4ae6-a163-41942d4a1ccc>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "metadata_plugin = pm.plugins['metadata']\n",
    "metadata_tabulate = metadata_plugin.actions['tabulate']\n",
    "stats_meta1 = metadata_tabulate(input=qual_control1.denoising_stats.view(Metadata))\n",
    "stats_meta1.visualization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><img onload=\"(function(div, url){\n",
       "if (typeof require !== 'undefined') {\n",
       "    var baseURL = require.toUrl('').split('/').slice(0, -2).join('/');\n",
       "} else {\n",
       "    var baseURL = JSON.parse(\n",
       "        document.getElementById('jupyter-config-data').innerHTML\n",
       "    ).baseUrl.slice(0, -1);\n",
       "}\n",
       "url = baseURL + url;\n",
       "fetch(url).then(function(res) {\n",
       "    if (res.status === 404) {\n",
       "        div.innerHTML = 'Install QIIME 2 Jupyter extension with:<br />' +\n",
       "                        '<code>jupyter serverextension enable --py qiime2' +\n",
       "                        ' --sys-prefix</code><br />then restart your server.' +\n",
       "                        '<br /><br />(Interactive output not available on ' +\n",
       "                        'static notebook viewer services like nbviewer.)';\n",
       "    } else if (res.status === 409) {\n",
       "        div.innerHTML = 'Visualization no longer in scope. Re-run this cell' +\n",
       "                        ' to see the visualization.';\n",
       "    } else if (res.ok) {\n",
       "        url = res.url;\n",
       "        div.innerHTML = '<iframe src=\\'' + url + '\\' style=\\'' +\n",
       "                        'width: 100%; height: 700px; border: 0;\\'>' +\n",
       "                        '</iframe><hr />Open in a: <a href=\\'' + url + '\\'' +\n",
       "                        ' target=\\'_blank\\'>new window</a>'\n",
       "    } else {\n",
       "        div.innerHTML = 'Something has gone wrong. Check notebook server for' +\n",
       "                        ' errors.';\n",
       "    }\n",
       "});\n",
       "})(this.parentElement, '/qiime2/redirect?location=/tmp/qiime2-archive-mklsu3cm')\" src=\"\" /></div>"
      ],
      "text/plain": [
       "<visualization: Visualization uuid: 8fb65ec5-1576-4cdb-9191-e387c04bf9f7>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "stats_meta2 = metadata_tabulate(input=qual_control2.denoising_stats.view(Metadata))\n",
    "stats_meta2.visualization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "ft_plugin = pm.plugins['feature-table']\n",
    "ft_merge = ft_plugin.actions['merge']\n",
    "ft_merge_seqs = ft_plugin.actions['merge_seqs']\n",
    "ft_summarize = ft_plugin.actions['summarize']\n",
    "ft_tab_seqs = ft_plugin.actions['tabulate_seqs']\n",
    "\n",
    "table_merge = ft_merge(tables=[qual_control1.table, qual_control2.table])\n",
    "seqs_merge = ft_merge_seqs(data=[qual_control1.representative_sequences, qual_control2.representative_sequences])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><img onload=\"(function(div, url){\n",
       "if (typeof require !== 'undefined') {\n",
       "    var baseURL = require.toUrl('').split('/').slice(0, -2).join('/');\n",
       "} else {\n",
       "    var baseURL = JSON.parse(\n",
       "        document.getElementById('jupyter-config-data').innerHTML\n",
       "    ).baseUrl.slice(0, -1);\n",
       "}\n",
       "url = baseURL + url;\n",
       "fetch(url).then(function(res) {\n",
       "    if (res.status === 404) {\n",
       "        div.innerHTML = 'Install QIIME 2 Jupyter extension with:<br />' +\n",
       "                        '<code>jupyter serverextension enable --py qiime2' +\n",
       "                        ' --sys-prefix</code><br />then restart your server.' +\n",
       "                        '<br /><br />(Interactive output not available on ' +\n",
       "                        'static notebook viewer services like nbviewer.)';\n",
       "    } else if (res.status === 409) {\n",
       "        div.innerHTML = 'Visualization no longer in scope. Re-run this cell' +\n",
       "                        ' to see the visualization.';\n",
       "    } else if (res.ok) {\n",
       "        url = res.url;\n",
       "        div.innerHTML = '<iframe src=\\'' + url + '\\' style=\\'' +\n",
       "                        'width: 100%; height: 700px; border: 0;\\'>' +\n",
       "                        '</iframe><hr />Open in a: <a href=\\'' + url + '\\'' +\n",
       "                        ' target=\\'_blank\\'>new window</a>'\n",
       "    } else {\n",
       "        div.innerHTML = 'Something has gone wrong. Check notebook server for' +\n",
       "                        ' errors.';\n",
       "    }\n",
       "});\n",
       "})(this.parentElement, '/qiime2/redirect?location=/tmp/qiime2-archive-tbqykfer')\" src=\"\" /></div>"
      ],
      "text/plain": [
       "<visualization: Visualization uuid: 2d2f3759-6cc4-447a-b62f-372e248c8f07>"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ft_sum = ft_summarize(table=table_merge.merged_table)\n",
    "ft_sum.visualization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><img onload=\"(function(div, url){\n",
       "if (typeof require !== 'undefined') {\n",
       "    var baseURL = require.toUrl('').split('/').slice(0, -2).join('/');\n",
       "} else {\n",
       "    var baseURL = JSON.parse(\n",
       "        document.getElementById('jupyter-config-data').innerHTML\n",
       "    ).baseUrl.slice(0, -1);\n",
       "}\n",
       "url = baseURL + url;\n",
       "fetch(url).then(function(res) {\n",
       "    if (res.status === 404) {\n",
       "        div.innerHTML = 'Install QIIME 2 Jupyter extension with:<br />' +\n",
       "                        '<code>jupyter serverextension enable --py qiime2' +\n",
       "                        ' --sys-prefix</code><br />then restart your server.' +\n",
       "                        '<br /><br />(Interactive output not available on ' +\n",
       "                        'static notebook viewer services like nbviewer.)';\n",
       "    } else if (res.status === 409) {\n",
       "        div.innerHTML = 'Visualization no longer in scope. Re-run this cell' +\n",
       "                        ' to see the visualization.';\n",
       "    } else if (res.ok) {\n",
       "        url = res.url;\n",
       "        div.innerHTML = '<iframe src=\\'' + url + '\\' style=\\'' +\n",
       "                        'width: 100%; height: 700px; border: 0;\\'>' +\n",
       "                        '</iframe><hr />Open in a: <a href=\\'' + url + '\\'' +\n",
       "                        ' target=\\'_blank\\'>new window</a>'\n",
       "    } else {\n",
       "        div.innerHTML = 'Something has gone wrong. Check notebook server for' +\n",
       "                        ' errors.';\n",
       "    }\n",
       "});\n",
       "})(this.parentElement, '/qiime2/redirect?location=/tmp/qiime2-archive-kbypdl2q')\" src=\"\" /></div>"
      ],
      "text/plain": [
       "<visualization: Visualization uuid: 3889631a-8101-4234-b9a5-8f8aa1fee838>"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tab_seqs = ft_tab_seqs(data=seqs_merge.merged_data)\n",
    "tab_seqs.visualization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
